/*
********************************************************************************
* Copyright (C) 2021, xiang.D <dx_65535@163.com>.
* All right reserved.
*
* File Name   : builder.cc
* Author      :
* Version     : V1.0
* Description :
* Journal     : 2021-10-21 init v1.0
* Brief       : Blog: https://blog.csdn.net/qq_38750572?spm=1001.2014.3001.5343
* Others      :
                Compile command: g++ -Wl,--no-as-needed -std=c++11 builder.cc
********************************************************************************
*/
#include <string>
#include <iostream>

using namespace std;

typedef enum {
    ALLOCATION_MIN = 0,
    ALLOCATION_NORMAL,
    ALLOCATION_HIGH,
    ALLOCATION_MAX
} ENOTEBOOK_TYPE;

class CComputer
{
public:
    virtual ~CComputer() {}
    void   SetName(string value) { mName = value; }
    string GetName() { return mName; }
    void   SetWeight(string value) { mWeight = value; }
    string GetWeight() { return mWeight; }
    void   SetMemary(string value) { mMemary = value; }
    string GetMemary() { return mMemary; }
    void   SetHardDisk(string value) { mHardDisk = value; }
    string GetHardDisk() { return mHardDisk; }
    void   SetCpu(string value) { mCpu = value; }
    string GetCpu() { return mCpu; }

private:
    string mName;
    string mWeight;
    string mMemary;
    string mHardDisk;
    string mCpu;
};

class CComputerBuilder
{
public:

    virtual void BuildName() = 0;
    virtual void BuildWeight() = 0;
    virtual void BuildMemary() = 0;
    virtual void BuildHardisk() = 0;
    virtual void BuildHardiskHigh() = 0;
    virtual void BuildCpu() = 0;
    virtual CComputer* GetComputer() = 0;
};

class CThinkPadX13Builder : public CComputerBuilder
{
public:

    CThinkPadX13Builder()
    {
        mThinkPadX13 = new CComputer();
    }

    ~CThinkPadX13Builder()
    {
        delete mThinkPadX13;
    }

    void BuildName()
    {
        mThinkPadX13->SetName("ThinkPad X13");
    }

    void BuildWeight()
    {
        mThinkPadX13->SetWeight("1.3Kg");
    }

    void BuildMemary()
    {
        mThinkPadX13->SetMemary("32GB");
    }

    void BuildHardisk()
    {
        mThinkPadX13->SetHardDisk("512G");
    }

    void BuildHardiskHigh()
    {
        mThinkPadX13->SetHardDisk("1TB");
    }

    void BuildCpu()
    {
        mThinkPadX13->SetCpu("I5-10210U");
    }

    CComputer *GetComputer() {return mThinkPadX13;}

private:
    CComputer* mThinkPadX13;
};

class CMateBookXProBuilder : public CComputerBuilder
{
public:
    CMateBookXProBuilder()
    {
        mMateBookXPro = new CComputer();
    }

    ~ CMateBookXProBuilder()
    {
        delete mMateBookXPro;
    }

    void BuildName()
    {
        mMateBookXPro->SetName("MateBook X Pro");
    }

    void BuildWeight()
    {
        mMateBookXPro->SetWeight("1.33KG");
    }

    void BuildMemary()
    {
        mMateBookXPro->SetMemary("16G");
    }

    void BuildHardisk()
    {
        mMateBookXPro->SetHardDisk("1TB");
    }

    void BuildHardiskHigh()
    {
        mMateBookXPro->SetHardDisk("2TB");
    }

    void BuildCpu()
    {
        mMateBookXPro->SetCpu("i7-1165G7");
    }

    CComputer* GetComputer() { return mMateBookXPro; }

private:
    CComputer* mMateBookXPro;
};

class CDirector
{
public:
    CDirector(CComputerBuilder *pBuilder)
    {
        mBuilder = pBuilder;
    }

    void BuildComputer(ENOTEBOOK_TYPE notebookType)
    {
        mBuilder->BuildName();
        mBuilder->BuildWeight();
        mBuilder->BuildMemary();
        mBuilder->BuildCpu();

        if (notebookType == ALLOCATION_NORMAL)
        {
            mBuilder->BuildHardisk();
        } else if (notebookType == ALLOCATION_HIGH) {
            mBuilder->BuildHardiskHigh();
        } else {
            cout << "Error: No this type!" << endl;
        }

    }

private:
    CComputerBuilder* mBuilder;
};

static void show_params(CComputer *pComputer)
{
    cout << "---" << pComputer->GetName() << "---" << endl;
    cout << "Weight: " << pComputer->GetWeight() << endl;
    cout << "Memary: " << pComputer->GetMemary() << endl;
    cout << "Hard disk: " << pComputer->GetHardDisk() << endl;
    cout << "Cpu: " << pComputer->GetCpu() << endl;
    cout << endl;
}

int main(int argc, char *argv[])
{
    CThinkPadX13Builder *theComputerBuilder1 = new CThinkPadX13Builder();
    CDirector *theDirector1 = new CDirector(theComputerBuilder1);
    theDirector1->BuildComputer(ALLOCATION_HIGH);
    CComputer *theComputer1 =  theComputerBuilder1->GetComputer();
    show_params(theComputer1);
    delete theDirector1;
    delete theComputerBuilder1;

    CMateBookXProBuilder *theComputerBuilder2 = new CMateBookXProBuilder();
    CDirector *theDirector2 = new CDirector(theComputerBuilder2);
    theDirector2->BuildComputer(ALLOCATION_HIGH);
    CComputer *theComputer2 =  theComputerBuilder2->GetComputer();
    show_params(theComputer2);
    delete theDirector2;
    delete theComputerBuilder2;

    return 0;
}



